package com.middlegroup.payadmin.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.middlegroup.common.enums.ConfigKeyEnums;
import com.middlegroup.common.model.ResponseEntity;
import com.middlegroup.common.model.TransRequest;
import com.middlegroup.common.model.TransResult;
import com.middlegroup.common.utils.AesUtils;
import com.middlegroup.common.utils.Base64Utils;
import com.middlegroup.common.utils.RSAUtils;
import com.middlegroup.payadmin.mapper.SubjectMapper;
import com.middlegroup.payadmin.mapper.SystemCfgMapper;
import com.middlegroup.payadmin.pojo.po.Subject;
import com.middlegroup.payadmin.pojo.po.SystemCfg;
import com.middlegroup.payadmin.service.SystemCfgService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 *
 * @author pc
 * @date 2019/1/15
 */
@Service
@Slf4j
public class SystemCfgImpl extends ServiceImpl<SystemCfgMapper, SystemCfg> implements SystemCfgService {

    @Resource
    private SystemCfgMapper systemCfgMapper;

    @Resource
    private SubjectMapper subjectMapper;


    @Override
    @CachePut(value = "pay_platform", key = "'system:config'", unless = "#result eq null")
    public Map<String, Map<String, String>> refreshConfigs() {
        Map<String, Map<String, String>> configs = null;
        //查询所有配置
        List<SystemCfg> configLists = systemCfgMapper.selectList(null);
        if (!CollectionUtils.isEmpty(configLists)) {
            configs = new HashMap<>();
            for (SystemCfg systemCfg : configLists) {
                if (configs.containsKey(systemCfg.getCategory())) {
                    //如果放入了则去除对应category的map
                    Map<String, String> config = configs.get(systemCfg.getCategory());
                    if (config.containsKey(systemCfg.getName())) {
                        //有则跳过
                        continue;
                    } else {
                        //无则put
                        config.put(systemCfg.getName(), systemCfg.getContent());
                    }
                } else {
                    Map<String, String> config = new HashMap<>();
                    config.put(systemCfg.getName(), systemCfg.getContent());
                    configs.put(systemCfg.getCategory(), config);
                }
            }
        }
        return configs;
    }

    @Override
    @Cacheable(value = "pay_platform", key = "'system:config:'+#p0.toString()+#p1.toString()", unless = "#result eq null")
    public SystemCfg getConfig(String category, String name) {
        SystemCfg systemCfgFind = new SystemCfg();
        systemCfgFind.setCategory(category);
        systemCfgFind.setName(name);
        SystemCfg systemCfg = systemCfgMapper.selectOne(systemCfgFind);
        return systemCfg;
    }

    @Override
    public String getConfigString(String category, String name) {
       SystemCfg systemCfg = getConfig(category,name);
       if (null != systemCfg){
           return systemCfg.getContent();
       }
       return null;
    }

    /**
     * 请求主体服务端
     * 对业务参数加密，请求加签名等
     *
     * @param method  请求的方法
     * @param request 交易参数
     * @return
     */
    @Override
    public TransResult post(String method, TransRequest request) {
        String subjectCode = request.getSubjectCode();
        if (StringUtils.isBlank(subjectCode)) {
            log.error("subjectCode不能为空!");
            return null;
        }

        //接口安全处理，数据Aes加密、rsa加签名
        //获取本主体的私钥、主体服务端公钥（根据subjectCode获取）
        Subject subject = subjectMapper.getSubjectByCode(subjectCode);
        if (null == subject) {
            log.error("subjectCode未定义，请联系管理员!");
            return null;
        }

        String url = subject.getServiceUrl();
        if (StringUtils.isBlank(url)) {
            log.error("主体网关未配置，请联系管理员!");
            return null;
        }
        String subjectpayEndPublicKey = subject.getRsaPubKey();
        //获取中台私钥
        ConfigKeyEnums configKeyEnums = ConfigKeyEnums.valueOf(ConfigKeyEnums.PAY_PLATFORM_RSA_PRI_KEY.name());
        String privateKeyStr = getConfigString(configKeyEnums.getCategory(), configKeyEnums.getName());
        if (StringUtils.isBlank(privateKeyStr)) {
            log.error("支付中台平台私钥未配置，请联系管理员!");
            return null;
        }

        String aesKey = RandomStringUtils.randomAlphanumeric(16);
        String reqData = null;
        String oldAesKey = aesKey;
        //使用明文aesKey加密业务数据
        try {
            reqData = AesUtils.encrypt(JSONObject.toJSONString(request), aesKey);
        } catch (Exception e) {
            log.error("AES加密业务数据失败!", e);
            return null;
        }
        //使用主体服务端公钥加密aesKey
        try {
            aesKey = new String(Base64Utils.encode(RSAUtils.encryptByPublicKey(aesKey.getBytes("UTF-8"), subjectpayEndPublicKey)));
        } catch (Exception e) {
            log.error("RSA加密AES 密钥失败!", e);
            return null;
        }
        MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();
        postParameters.add("aesKey", aesKey);
        postParameters.add("subjectCode", subjectCode);
        postParameters.add("method", method);
        postParameters.add("reqData", reqData);

        Map<String, String> params = new TreeMap<String, String>();
        params.put("aesKey", aesKey);
        params.put("subjectCode", subjectCode);
        params.put("method", method);
        params.put("reqData", reqData);
        String jsoStr = JSONObject.toJSONString(params);

        PrivateKey privateKey = RSAUtils.readPrivateKey(privateKeyStr);
        String sign = null;
        try {
            sign = RSAUtils.sign("SHA1WithRSA", jsoStr.getBytes("UTF-8"), privateKey);
        } catch (Exception e) {
            log.error("rsa签名失败!", e);
            return null;
        }
        postParameters.add("sign", sign);
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity res = null;


        try {
            res = restTemplate.postForObject(url, postParameters, ResponseEntity.class);
        } catch (Exception e) {
            log.error("调用主体服务端接口失败", e);
        }
        if (null == res) {
            //默认交易处理中
            log.error("主体服务端接口返回空");
            return null;
        }

        TransResult resResult = null;
        if (StringUtils.equals(ResponseEntity.STATUS_FAIL, res.getStatus())) {
            //失败,中台服务一定要保证status=0一定是失败
            log.error("主体服务端接口接口异常!");
            return null;
        }
        if (StringUtils.equals(ResponseEntity.STATUS_OK, res.getStatus())) {
            //取data判断
            Object data = res.getData();
            if (null == data) {
                log.error("主体服务未返回业务结果!");
                return null;
            }
            String dataEncrypt = (String) res.getData();
            String dataDecrypt = null;
            //解密
            try {
                dataDecrypt = AesUtils.decrypt(dataEncrypt, oldAesKey);
            } catch (Exception e) {
                log.error("主体返回业务数据Aes解密失败", e);
                return null;
            }
            if (StringUtils.isBlank(dataDecrypt)) {
                log.error("主体返回业务数据Aes解密失败");
                return null;
            }
            //解密成功转换成transResult

            try {
                resResult = JSONObject.parseObject(dataDecrypt,TransResult.class);
            } catch (Exception e) {
                log.error("主体返回业务数据转换失败", e);
                return null;
            }
        }
        return resResult;
    }
}
